package compiler

import (
	"kumachan/lang/source"
	"kumachan/lang/typsys"
	"kumachan/interpreter/program"
)

func compileFunction (
	f     *program.Function,
	hdr   *funHeader,
	impl  funImpl,
	fd    fragmentDraft,
	ctx   *NsHeaderMap,
	errs  *source.Errors,
) {
	switch I := impl.(type) {
	case funImplAstExpr:
		var v = compileFunImplAstExpr(I, hdr, fd, ctx, errs)
		f.SetExprBasedValue(v)
	case funImplLibraryNative:
		f.SetNativeValueById(I.Id)
	case funImplLoadedAsset:
		panic("not implemented") // TODO
	default:
		panic("impossible branch")
	}
}

func compileFunImplAstExpr (
	impl  funImplAstExpr,
	hdr   *funHeader,
	fd    fragmentDraft,
	ctx   *NsHeaderMap,
	errs  *source.Errors,
) *program.ExprBasedFunctionValue {
	var in_exp = hdr.inputsExplicit
	var in_imp = hdr.inputsImplicit
	var out = hdr.output
	var params = hdr.typeParams
	var ec = createExprContext(params, fd, ctx)
	var in = [...] [] *program.Binding { nil, nil }
	for i, fields := range ([...] *typsys.Fields { &in_exp, &in_imp }) {
		in[i] = make([] *program.Binding, len(fields.FieldList))
		for j, field := range fields.FieldList {
			var name = field.Name
			var t = typsys.CertainType { Type: field.Type }
			var loc = field.Info.Location
			in[i][j] = ec.createBinding(name, t, loc)
		}
	}
	var in_args, in_ctx = in[0], in[1]
	var expr = impl.Expr
	var expected = out.type_
	var cc = createExprCheckContext(expected, ec)
	var output, err = checkExpr(expr, cc)
	if err != nil {
		source.ErrorsJoin(errs, err)
		return nil
	} else {
		return &program.ExprBasedFunctionValue {
			InputArgs: in_args,
			InputCtx:  in_ctx,
			Output:    output,
		}
	}
}


